﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Freeform;

namespace Space_in_Shaders
{
    public class SpaceWorld : World
    {
        public Viewport2D View { get; set; }
        public PlayerShip Player { get; set; }
        public EnemyShip Enemy { get; set; }
        public Int32 Score { get; set; }
        public Int32 SpawnRate { get; set; }
        public Int32 NextSpawn { get; set; }
        public Single SpawnMulti { get; set; }
        public Single SpawnDist { get; set; }
        public Overlay Overlay { get; set; }
        public Crosshair XHair { get; set; }
        public Entity StarBackground { get; set; }
        public new Game Game { get; set; }
        public Single BoundaryLeft { get; set; }
        public Single BoundaryRight { get; set; }
        public Single BoundaryTop { get; set; }
        public Single BoundaryBottom { get; set; }
        public Single PanDistance { get; set; }
        public Single PitchDistance { get; set; }
        public Single VolumeDistance { get; set; }

        public SoundEffect[] LaserEffect { get; set; }
        public SoundEffect[] MissileEffect { get; set; }
        public SoundEffect[] ExplosionEffect { get; set; }

        public SpaceWorld(Game game)
            :base (game)
        {
            Game = game;
            BackgroundColour = Color.Black;
            Player = new PlayerShip(this);
            
            View = new Viewport2D(this);
            View.Camera.SpatialProperties.Size = new Vector2(Game.GraphicsDeviceManager.PreferredBackBufferWidth, Game.GraphicsDeviceManager.PreferredBackBufferHeight) * 0.32f;
            View.Camera.CentreCamera(Player.SpatialProperties.Position);
            View.Depth = 0.8f;
            View.SpriteSorting = SpriteSortMode.BackToFront;
            CollisionChecks = Freeform.CollisionChecks.OneWay;
            CollisionDetection.ProcessHandling = ProcessHandling.Sequential;
            SpawnRate = 2800;
            SpawnMulti = 0.98f;
            SpawnDist = 300;
            NextSpawn = 0;
            XHair = new Crosshair(this);
            Overlay = new Overlay(this);
            ComponentList.PrioritySorting = false;

            BoundaryLeft = -341f;
            BoundaryRight = 341f;
            BoundaryTop = -246f;
            BoundaryBottom = 246f;

            PanDistance = 300f;
            PitchDistance = 800f;
            VolumeDistance = 65000f;

            LaserEffect = new SoundEffect[] { Game.Content.Load<SoundEffect>("Audio/Laser1") };
            MissileEffect = new SoundEffect[] { Game.Content.Load<SoundEffect>("Audio/Missile1"), Game.Content.Load<SoundEffect>("Audio/Missile2") };
            ExplosionEffect = new SoundEffect[] { Game.Content.Load<SoundEffect>("Audio/Explosion1"), Game.Content.Load<SoundEffect>("Audio/Explosion2") };

            StarBackground = new Entity(this);
            Game.LoadAnimation(StarBackground, "StarBackgroundA");
            StarBackground.Actor.Depth = 1f;
            StarBackground.SpatialProperties.Size = new Vector2(BoundaryRight - BoundaryLeft, BoundaryBottom - BoundaryTop);
            StarBackground.SpatialProperties.Position = new Vector2(BoundaryRight + BoundaryLeft, BoundaryBottom + BoundaryTop) / 2;
            
        }


        public override void Update(GameTime time)
        {
            base.Update(time);

            // Set camera location.
            View.Camera.CentreCamera(Player.SpatialProperties.Position);
            if (View.Camera.SpatialProperties.Position.X < BoundaryLeft)
                View.Camera.SpatialProperties.Position = new Vector2(BoundaryLeft, View.Camera.SpatialProperties.Position.Y);
            else if (View.Camera.SpatialProperties.Position.X + View.Camera.SpatialProperties.Size.X > BoundaryRight)
                View.Camera.SpatialProperties.Position = new Vector2(BoundaryRight - View.Camera.SpatialProperties.Size.X, View.Camera.SpatialProperties.Position.Y);
            if (View.Camera.SpatialProperties.Position.Y < BoundaryTop)
                View.Camera.SpatialProperties.Position = new Vector2(View.Camera.SpatialProperties.Position.X, BoundaryTop);
            else if (View.Camera.SpatialProperties.Position.Y + View.Camera.SpatialProperties.Size.Y > BoundaryBottom)
                View.Camera.SpatialProperties.Position = new Vector2(View.Camera.SpatialProperties.Position.X, BoundaryBottom - View.Camera.SpatialProperties.Size.Y);


            if (!Player.IsDestroyed)
                NextSpawn -= time.ElapsedGameTime.Milliseconds;

            // Added random spawns. Renamed ship images to an Integer before Classname format so as to avoid conflicting with the wildcard (*) after class name in Game.LoadAnimation();
            // nulling Ship.Actor to allow new animations to be loaded is probably poor form.
            if (NextSpawn < 0)
            {
                NextSpawn = SpawnRate;
                SpawnRate = (Int32)(SpawnRate * SpawnMulti);

                if (Game.Random.Int32(0, 4) != 3)
                {
                    EnemyShip Ship = new EnemyShip(this);
                    Ship.SpatialProperties.Position = View.Camera.SpatialProperties.Position + View.Camera.SpatialProperties.Size / 2 + Util.Vec2InDir(Game.Random.Single(0, MathHelper.TwoPi)) * SpawnDist;
                    Ship.SpatialProperties.Direction = Game.Random.Single(0, MathHelper.TwoPi);
                }
                else
                {
                    EnemyBomber Bomber = new EnemyBomber(this);
                    Bomber.SpatialProperties.Position = View.Camera.SpatialProperties.Position + View.Camera.SpatialProperties.Size / 2 + Util.Vec2InDir(Game.Random.Single(0, MathHelper.TwoPi)) * SpawnDist;
                    Bomber.SpatialProperties.Direction = Game.Random.Single(0, MathHelper.TwoPi);
                }
            }

            Vector4 Overlay = View.ColourOverlay.ToVector4();
            Overlay += (Vector4.One - Overlay) * 0.2f;
            View.ColourOverlay = new Color(Overlay);

            if (Player.IsDestroyed && Game.Input.KeyState_Current.IsKeyDown(Keys.Space))
            {
                Dispose();
                new SpaceWorld(Game);
            }
        }

        protected override void OnDispose()
        {
            base.OnDispose();

            Overlay.Dispose();
        }


        public void PlaySound(SoundEffect Sound, Vector2 Position, Single VolumeScaling)
        {
            Vector2 Diff = Position - View.Camera.SpatialProperties.Position - View.Camera.SpatialProperties.Size / 2;
            Single Pan = Diff.X / PanDistance;
            Single Pitch = -Diff.Y / PitchDistance;
            Single Volume = 1 - (Diff.LengthSquared() / VolumeDistance);

            if (Volume < 0) return;
            if (Pan > 1f) return;
            if (Pan < -1f) return;
            if (Pitch > 1f) return;
            if (Pitch < -1f) return;

            Sound.Play(VolumeScaling * Volume, Pitch, Pan);
        }
    }
}
